import os, re, csv, zipfile, datetime
#changed to get applied instead of accepted.
#changed all instances of the word "accepted" to "applied"
#changed name of statistics.js to zipcodes.js
#changed zipcode instance count check to also check validity of data.
#added easyVersion function to remove laborious list making to execute the file.

def easyVersion():
    directory = os.listdir(os.getcwd())
    classData = filter(lambda x: x.endswith('.csv'),directory)
    tempZipData = filter(lambda x: x.endswith('.zip'),directory)
    zipData = [[item,''] for item in tempZipData]
    makeZipCodeFile(classData, zipData)
    directory = os.listdir(os.getcwd())
    #remove all junk files made by unzipping
    for file in directory:
        if file.endswith('.dat'):
            os.remove(file)

def makeZipCodeFile(csvList, dataLookupTupleList):
    medZips = {}
    # Get all zip codes for all states
    for item in dataLookupTupleList:
        stateZips = getZipCodes(item[0], item[1])
        for zipCode in stateZips.values():
            if not re.match('[0-9A-Za-z]{5}', zipCode.code) or zipCode.coords == [] or zipCode.center == []:
                continue
            medZips[zipCode.code] = ZipCode(zipCode.coords, zipCode.center)
    # Enter the statistics from every academic year into finalZips
    for csvFile in csvList:
        getZipCodeStats(csvFile, medZips)
    
    # Remove any zipcodes that still have no interesting data
    finalZips = {}
    for zip, obj in medZips.items():
        if len(obj.gpas) >= 5 and len(obj.sats) >= 5 and obj.gpasLegal() and obj.satsLegal():
            finalZips[zip] = obj
    # Finally, write out file
    output = open('zipcodes.js','w')
    # Comment indicating date created
    currentDate = datetime.date.today()
    output.write('//Generated by mercerParser on: '+str(currentDate.month)+'/'+str(currentDate.day)+'/'+str(currentDate.year)+'\n')
    # Declare array
    output.write('var zipCodes = new Array();\n')
    for zip, obj in finalZips.items():
        # Declaration for an element in array
        output.write("zipCodes['"+zip+"'] = {")
        # Write out all sat scores for zip code
        output.write("sat:[")
        satString = ""
        for verbal, math in obj.sats:
            satString += "["+verbal+","+math+"],"
        output.write(satString.rstrip(","))
        output.write("],")
        # Write out applied for zip code
        output.write("applied:"+str(obj.applied)+",")
        # Write out enrolled for zip code
        output.write("enrolled:"+str(obj.enrolled)+",")
        # Write out gpas for zip code
        output.write("gpa:[")
        gpaString = ""
        for gpa in obj.gpas:
            gpaString += "["+gpa+"],"
        output.write(gpaString.rstrip(","))
        output.write("],")
        # Write out center for zip code
        output.write("center:["+obj.center[0]+","+obj.center[1]+"],")
        # Write out perimiter for zip code
        output.write("coords:[")
        coordString = ""
        for x, y in obj.coords:
            coordString += "["+x+","+y+"],"
        output.write(coordString.rstrip(","))
        output.write("]};\n")
    output.close()

# Pass in a csv for the education data. Data will be read in.
def getZipCodeStats(inputcsv, requestedzips):
    file = csv.reader(open(inputcsv))
    header = file.next()
    for line in file:
        satVerbal, satMath = line[4], line[5]
        gpa = line[17]
        applied, enrolled = line[8], line[20]
        zip = re.split('-', line[14])[0]
        # We can accept some empty fields, but the following four must be filled out:
        if satVerbal == '' or satMath == '' or zip == '' or gpa == '':
            continue
        # If we don't have bounds for this zipcode, we don't care about this person.
        if zip not in requestedzips:
            continue
        if enrolled == 'Y':
            requestedzips[zip].enrolled += 1
        if applied == 'Y':
            requestedzips[zip].applied += 1
        requestedzips[zip].gpas.append(gpa)
        requestedzips[zip].sats.append([satVerbal, satMath])

# Pass in the name of a zipfile, or just a .dat file.
# Write contents of file as .js file.
def getZipCodes(datafilename, lookupfilename = ""):
    if(lookupfilename == ""):
        datafilename, lookupfilename = unZip(datafilename)

    datafile = open(datafilename)
    firstline = datafile.readline()
    secondline = datafile.readline()
    datafile.close()
    # Second line at least should be rather long.
    # If it isn't, then the datafilename and lookup filename are mixed up.
    if len(secondline) < 20:
        temp = datafilename
        datafilename = lookupfilename
        lookupfilename = temp

    lookupfile = open(lookupfilename)
    table = {}
    
    while True:
        index = lookupfile.readline().strip()
        if index == '':
            break
        zipcode = lookupfile.readline().strip()
        table[index] = ZipCodeCoords(zipcode.strip('"'))
        line = lookupfile.readline()
        while line.strip() != '':
            line = lookupfile.readline()
    
    lookupfile.close()
    
    datafile = open(datafilename)
    
    centerset = False
    index = -1
    for line in datafile:
        splitline = re.split('[^-.0-9END+]*', line.strip())
        if len(splitline) > 2:
            index, centerx, centery = splitline
            if index not in table:
                continue
            table[index].center = [centerx, centery]
            centerset = True
        elif len(splitline) == 1 and (splitline[0] == 'END' or splitline[0] == ''):
            centerset = False
        elif len(splitline) == 1 and splitline[0] != '':
            index = splitline[0]
            centerset = False
        elif len(splitline) == 2 and centerset == False:
            if index not in table:
                continue
            table[index].center = splitline
        elif len(splitline) == 2:
            if index not in table:
                continue
            table[index].coords.append(splitline)
        else:
            raise Exception("Input file does not match expected format. Find a smart guy to fix it.")
    
    datafile.close()
    
    return table

def unZip(filename):
    zippy = zipfile.ZipFile(filename)
    zippy.extractall()
    return zippy.namelist()

class ZipCode:
    def __init__(self, perimitercoords, centercoords):
        self.applied = 0
        self.enrolled = 0
        self.gpas = []
        self.sats = []
        self.coords = perimitercoords
        self.center = centercoords
    
    def satsLegal(self):
        for numbers in self.sats:
            try:
                float(numbers[0])
                float(numbers[1])
            except ValueError as e:
                print 'One of the sats in your data file was incorrectly formatted.'
                print e
                return False
        return True
    
    def gpasLegal(self):
        for number in self.gpas:
            try:
                float(number)
            except ValueError as e:
                print 'One of the gpas in your data file was incorrectly formatted.'
                print e
                return False
        return True

class ZipCodeCoords:
    def __init__(self, name):
        self.code = name
        self.coords = []
        self.center = []